#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import socket
import threading
import time
from datetime import datetime
from typing import Callable, Optional, Dict, Any

from ..server.data_parse import is_modbus_data, parse_modbus_rtu


class TcpServerManager:
    """TCP服务器管理类"""
    
    def __init__(self, message_callback: Optional[Callable] = None):
        """
        初始化TCP服务器管理器
        
        Args:
            message_callback: 消息回调函数，用于向GUI发送日志消息
                             函数签名: callback(message: str, level: str = "INFO", msg_type: str = "normal")
                             msg_type可以是: "normal", "send", "receive", "error"
        """
        self.server_socket = None
        self.server_instance = None
        self.running = False
        self.client_count = 0
        self.clients = {}  # {client_address: client_socket}
        self.client_ids = {}  # {client_id: client_address} - 客户端ID映射
        self.address_to_id = {}  # {client_address: client_id} - 地址到ID的反向映射
        self.next_client_id = 1  # 下一个客户端ID
        self.clients_lock = threading.Lock()

        # 回调函数
        self.message_callback = message_callback or self._default_callback
        
    def _default_callback(self, message: str, level: str = "INFO", msg_type: str = "normal"):
        """默认回调函数，打印到控制台"""
        timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3]
        print(f"[{timestamp}] {level}: {message}")
    
    def start_server(self, host: str = "0.0.0.0", port: int = 9010) -> bool:
        """
        启动TCP服务器
        
        Args:
            host: 监听IP地址
            port: 监听端口
            
        Returns:
            bool: 启动是否成功
        """
        try:
            if self.server_instance:
                self.stop_server()
            
            self.server_instance = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_instance.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.server_instance.bind((host, port))
            self.server_instance.listen(5)
            
            self.running = True
            self.message_callback(f"TCP服务器已启动，监听 {host}:{port}")
            
            # 启动服务器接受连接的线程
            threading.Thread(target=self._accept_connections, daemon=True).start()
            
            return True
            
        except Exception as e:
            self.message_callback(f"启动TCP服务器失败: {e}", "ERROR", "error")
            return False
    
    def stop_server(self):
        """停止TCP服务器"""
        try:
            self.running = False
            
            # 关闭所有客户端连接
            with self.clients_lock:
                for client_socket in self.clients.values():
                    try:
                        client_socket.close()
                    except:
                        pass
                self.clients.clear()
                self.client_ids.clear()
                self.address_to_id.clear()
                self.client_count = 0
            
            if self.server_instance:
                self.server_instance.close()
                self.server_instance = None
            
            self.message_callback("TCP服务器已停止")
            
        except Exception as e:
            self.message_callback(f"停止TCP服务器错误: {e}", "ERROR", "error")
    
    def _accept_connections(self):
        """接受客户端连接的线程"""
        while self.running and self.server_instance:
            try:
                client_socket, client_address = self.server_instance.accept()
                
                with self.clients_lock:
                    # 清理同一IP的旧连接
                    self._cleanup_client_by_ip(client_address[0])

                    # 为新客户端分配唯一ID
                    client_id = self.next_client_id
                    self.next_client_id += 1

                    # 添加客户端到映射表
                    self.clients[client_address] = client_socket
                    self.client_ids[client_id] = client_address
                    self.address_to_id[client_address] = client_id
                    self.client_count += 1

                self.message_callback(f"🔗 客户端 {client_address} 已连接 [ID: {client_id}] [总连接数: {self.client_count}]")
                
                # 为每个客户端创建处理线程
                threading.Thread(target=self._handle_client, 
                               args=(client_socket, client_address), daemon=True).start()
                
            except Exception as e:
                if self.running:
                    self.message_callback(f"接受连接错误: {e}", "ERROR", "error")
                break
    
    def _handle_client(self, client_socket: socket.socket, client_address: tuple):
        """处理客户端连接"""
        # 获取客户端ID
        client_id = self.address_to_id.get(client_address, "未知")

        try:
            self.message_callback(f"🔗 设备 {client_address} [ID: {client_id}] 连接成功")

            while self.running:
                data = client_socket.recv(1024)
                if data:
                    self.message_callback(f"📨 收到来自 {client_address} 的数据: {data.hex().upper()}", 
                                        "INFO", "receive")
                    
                    # 判断是否为Modbus数据并解析
                    if is_modbus_data(data):
                        parsed = parse_modbus_rtu(data)
                        self._log_modbus_data(parsed)
                    else:
                        self.message_callback("📄 非Modbus数据", "INFO", "receive")
                else:
                    self.message_callback(f"🔌 设备 {client_address} 断开连接", "INFO", "receive")
                    break
                    
        except ConnectionResetError:
            self.message_callback(f"⚠️  设备 {client_address} 强制断开连接", "INFO", "receive")
        except Exception as e:
            self.message_callback(f"❌ 处理设备 {client_address} 时发生错误: {e}", "ERROR", "error")
        finally:
            client_socket.close()
            with self.clients_lock:
                client_id = self.address_to_id.get(client_address)
                self._remove_client(client_address)

            self.message_callback(f"🔌 设备 {client_address} [ID: {client_id}] 连接已关闭 [当前连接数: {self.client_count}]",
                                "INFO", "receive")
    
    def _log_modbus_data(self, parsed_result: Dict[str, Any]):
        """记录Modbus解析结果"""
        self.message_callback("┌─ Modbus解析结果 ─────────────────────", "INFO", "receive")
        
        if "error" in parsed_result:
            self.message_callback(f"│ ❌ 解析错误: {parsed_result['error']}", "INFO", "receive")
        else:
            self.message_callback(f"│ 📍 设备地址: {parsed_result.get('slave_id', 'N/A')}", "INFO", "receive")
            self.message_callback(f"│ 🔧 功能码: {parsed_result.get('function_code', 'N/A')} - {parsed_result.get('function', 'N/A')}", "INFO", "receive")
            self.message_callback(f"│ ✅ CRC校验: {'通过' if parsed_result.get('crc_valid', False) else '失败'}", "INFO", "receive")
            
            # 显示寄存器数据
            if "registers" in parsed_result:
                self.message_callback(f"│ 📊 寄存器数量: {len(parsed_result['registers'])}", "INFO", "receive")
                for i, reg_val in enumerate(parsed_result['registers']):
                    hex_val = parsed_result.get('register_hex', [''])[i] if i < len(parsed_result.get('register_hex', [])) else f"0x{reg_val:04X}"
                    self.message_callback(f"│    寄存器[{i}]: {reg_val} ({hex_val})", "INFO", "receive")
            
            # 显示线圈数据
            if "coil_data" in parsed_result:
                self.message_callback(f"│ 🔘 线圈数据: {parsed_result['coil_data']}", "INFO", "receive")
        
        self.message_callback("└─────────────────────────────────────", "INFO", "receive")
    
    def broadcast_data(self, data_str: str) -> bool:
        """
        广播数据到所有客户端
        
        Args:
            data_str: 要发送的数据字符串
            
        Returns:
            bool: 发送是否成功
        """
        if not data_str.strip():
            return False
        
        try:
            # 解析输入数据
            byte_data, data_type, original_data = self._parse_data_input(data_str)
            
            with self.clients_lock:
                if not self.clients:
                    self.message_callback("❌ 没有客户端连接，无法广播", "ERROR", "error")
                    return False
                
                success_count = 0
                for client_address, client_socket in self.clients.items():
                    try:
                        client_socket.send(byte_data)
                        success_count += 1
                    except Exception as e:
                        self.message_callback(f"❌ 向客户端 {client_address} 发送失败: {e}", "ERROR", "error")
                
                if data_type == 'hex':
                    self.message_callback(f"📤 广播十六进制数据: {original_data}", "INFO", "send")
                    self.message_callback(f"   字节数据: {byte_data.hex().upper()}", "INFO", "send")
                else:
                    self.message_callback(f"📤 广播文本数据: {original_data}", "INFO", "send")
                    self.message_callback(f"   字节数据: {byte_data.hex().upper()}", "INFO", "send")
                
                self.message_callback(f"✅ 数据已广播到 {success_count}/{len(self.clients)} 个客户端", "INFO", "send")
                return success_count > 0
                
        except Exception as e:
            self.message_callback(f"广播数据失败: {e}", "ERROR", "error")
            return False
    
    def _parse_data_input(self, data_input: str) -> tuple:
        """解析输入的数据，支持文本和十六进制格式"""
        if data_input.startswith('text:'):
            # 文本数据
            text_data = data_input[5:]  # 去掉 'text:' 前缀
            return text_data.encode('utf-8'), 'text', text_data
        else:
            # 尝试解析为十六进制数据
            try:
                hex_str = data_input.replace(' ', '').replace('-', '').replace(':', '')
                if len(hex_str) % 2 != 0:
                    hex_str = '0' + hex_str
                byte_data = bytes.fromhex(hex_str)
                return byte_data, 'hex', data_input
            except ValueError:
                # 如果不是有效的十六进制，当作文本处理
                return data_input.encode('utf-8'), 'text', data_input
    
    def get_client_count(self) -> int:
        """获取当前客户端连接数"""
        return self.client_count
    
    def is_running(self) -> bool:
        """检查服务器是否正在运行"""
        return self.running and self.server_instance is not None

    def get_client_list(self) -> list:
        """
        获取客户端列表

        Returns:
            list: 客户端信息列表，每个元素包含 (client_id, address, status)
        """
        with self.clients_lock:
            client_list = []
            for client_id, address in self.client_ids.items():
                socket_obj = self.clients.get(address)
                status = "在线" if socket_obj else "离线"
                client_list.append((client_id, address, status))
            return client_list

    def _cleanup_client_by_ip(self, client_ip: str):
        """
        清理指定IP的所有旧连接

        Args:
            client_ip: 客户端IP地址
        """
        clients_to_remove = []

        # 查找所有相同IP的连接
        for addr, socket_obj in self.clients.items():
            if addr[0] == client_ip:  # 比较IP地址（忽略端口）
                clients_to_remove.append(addr)

        # 清理旧连接
        for addr in clients_to_remove:
            old_client_id = self.address_to_id.get(addr)
            old_socket = self.clients.get(addr)

            # 关闭旧连接
            if old_socket:
                try:
                    old_socket.close()
                except:
                    pass

            # 从映射中删除
            if addr in self.clients:
                del self.clients[addr]
                self.client_count -= 1
            if old_client_id and old_client_id in self.client_ids:
                del self.client_ids[old_client_id]
            if addr in self.address_to_id:
                del self.address_to_id[addr]

            if old_client_id:
                self.message_callback(f"🔄 清理旧连接 [ID: {old_client_id}] {addr}")

    def send_to_client(self, client_identifier, data_input: str) -> bool:
        """
        向指定客户端发送数据

        Args:
            client_identifier: 客户端标识符（ID或地址）
            data_input: 要发送的数据

        Returns:
            bool: 发送是否成功
        """
        with self.clients_lock:
            target_client, target_addr, target_id = self._find_client_by_identifier(client_identifier)

            if target_client:
                try:
                    # 解析输入数据
                    byte_data, data_type, original_data = self._parse_data_input(data_input)
                    target_client.send(byte_data)

                    self.message_callback(f"✅ 数据已发送给客户端 [ID: {target_id}] {target_addr}", "INFO", "send")
                    self.message_callback(f"📤 发送数据: {byte_data.hex().upper()}", "INFO", "send")

                    if data_type == 'text':
                        self.message_callback(f"📝 文本内容: {original_data}", "INFO", "send")

                    return True

                except Exception as e:
                    self.message_callback(f"❌ 发送数据给客户端 [ID: {target_id}] {target_addr} 失败: {e}", "ERROR", "error")
                    return False
            else:
                self.message_callback(f"❌ 未找到客户端: {client_identifier}", "ERROR", "error")
                return False

    def broadcast_to_all(self, data_input: str) -> bool:
        """
        向所有客户端广播数据

        Args:
            data_input: 要广播的数据

        Returns:
            bool: 广播是否成功
        """
        with self.clients_lock:
            if not self.clients:
                self.message_callback("❌ 没有客户端连接，无法广播消息", "ERROR", "error")
                return False

            try:
                # 解析输入数据
                byte_data, data_type, original_data = self._parse_data_input(data_input)

                disconnected_clients = []
                success_count = 0

                for addr, client_socket in self.clients.items():
                    try:
                        client_socket.send(byte_data)
                        client_id = self.address_to_id.get(addr, "未知")
                        self.message_callback(f"✅ 数据已广播给客户端 [ID: {client_id}] {addr}", "INFO", "send")
                        success_count += 1
                    except Exception as e:
                        client_id = self.address_to_id.get(addr, "未知")
                        self.message_callback(f"❌ 向客户端 [ID: {client_id}] {addr} 广播失败: {e}", "ERROR", "error")
                        disconnected_clients.append(addr)

                # 移除断开连接的客户端
                for addr in disconnected_clients:
                    self._remove_client(addr)

                self.message_callback(f"📤 广播数据: {byte_data.hex().upper()}", "INFO", "send")
                if data_type == 'text':
                    self.message_callback(f"📝 文本内容: {original_data}", "INFO", "send")

                self.message_callback(f"📊 广播完成: {success_count}/{len(self.clients)} 客户端", "INFO", "send")

                return success_count > 0

            except Exception as e:
                self.message_callback(f"❌ 广播数据失败: {e}", "ERROR", "error")
                return False

    def _find_client_by_identifier(self, identifier):
        """
        根据客户端ID或地址查找客户端

        Args:
            identifier: 客户端标识符（ID或地址字符串）

        Returns:
            tuple: (client_socket, client_address, client_id)
        """
        target_client = None
        target_addr = None
        target_id = None

        # 尝试解析为客户端ID（数字）
        try:
            client_id = int(identifier)
            if client_id in self.client_ids:
                target_addr = self.client_ids[client_id]
                target_client = self.clients.get(target_addr)
                target_id = client_id
        except ValueError:
            # 不是数字，按地址查找
            pass

        # 如果按ID没找到，尝试按地址查找
        if target_client is None:
            identifier_str = str(identifier)
            for addr, client_socket in self.clients.items():
                addr_str = str(addr)
                if addr_str == identifier_str or identifier_str in addr_str:
                    target_client = client_socket
                    target_addr = addr
                    target_id = self.address_to_id.get(addr)
                    break

        return target_client, target_addr, target_id

    def _remove_client(self, client_address: tuple):
        """
        移除客户端连接

        Args:
            client_address: 客户端地址
        """
        client_id = self.address_to_id.get(client_address)

        if client_address in self.clients:
            del self.clients[client_address]
            self.client_count -= 1
        if client_id and client_id in self.client_ids:
            del self.client_ids[client_id]
        if client_address in self.address_to_id:
            del self.address_to_id[client_address]

    def disconnect_client(self, client_id: int) -> bool:
        """
        断开指定客户端连接

        Args:
            client_id: 客户端ID

        Returns:
            bool: 断开成功返回True，失败返回False
        """
        try:
            with self.clients_lock:
                # 根据ID查找客户端
                client_address = None
                for addr, cid in self.address_to_id.items():
                    if cid == client_id:
                        client_address = addr
                        break

                if client_address and client_address in self.clients:
                    # 关闭客户端连接
                    client_socket = self.clients[client_address]
                    try:
                        client_socket.close()
                    except:
                        pass

                    # 移除客户端记录
                    self._remove_client(client_address)

                    self.message_callback(f"✅ 已断开客户端 [ID: {client_id}] {client_address}")
                    return True
                else:
                    self.message_callback(f"❌ 未找到客户端 [ID: {client_id}]", "ERROR", "error")
                    return False

        except Exception as e:
            self.message_callback(f"❌ 断开客户端失败: {e}", "ERROR", "error")
            return False

    def disconnect_all_clients(self) -> int:
        """
        断开所有客户端连接

        Returns:
            int: 断开的客户端数量
        """
        try:
            with self.clients_lock:
                client_count = len(self.clients)

                # 关闭所有客户端连接
                for client_socket in self.clients.values():
                    try:
                        client_socket.close()
                    except:
                        pass

                # 清空所有客户端记录
                self.clients.clear()
                self.client_ids.clear()
                self.address_to_id.clear()
                self.client_count = 0

                if client_count > 0:
                    self.message_callback(f"✅ 已断开所有客户端连接，共 {client_count} 个")

                return client_count

        except Exception as e:
            self.message_callback(f"❌ 断开所有客户端失败: {e}", "ERROR", "error")
            return 0
